package com.loby.util;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
//import com.loby.monitor.operator.module.RedisRealData;
import com.loby.data.redis.pojo.PollutentParam;
import com.loby.data.redis.pojo.RedisRealData;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.*;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.lang.NonNull;
import org.springframework.stereotype.Component;

import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Stream;

import static java.util.Objects.isNull;
import static java.util.stream.Collectors.joining;

/**
 * 操作redis的工具类
 *
 * @author loby
 */
@Component
@Slf4j
public class RedisOperator {

    private static final String STATE_NAME_SPACE = "StationStatus";
    private static final String RDATA_NAME_SPACE = "RealData";
    private static final String DELIMIT = ":";
    private static final String ONLINE = "OnLine";
    private static final String STATE = "State";
    private static final String ONLINESTAMPT = "OnLineStamp";
    private static final String OFFLIMETIME = "OffLineTime";
    private static final String ONLIMETIME = "OnLineTime";
    private static RedisOperator operator;

    @Autowired
    private RedisTemplate<String, Object> fastJsonTemp;

    public RedisOperator() {
        operator = this;
    }

    public void setClientOnline(@NonNull String code, boolean stat) {
        try {
            Map<String,Integer> val = new HashMap<>(1);
            val.put(ONLINE,stat?1:0);
            fastJsonTemp.opsForValue().set(concat(STATE_NAME_SPACE, code, ONLINE), val);
        } catch (Exception e) {
            log.error("setClientOnline Failed! [" + code + "]", e);
        }
    }


    public void setClientStatus(@NonNull String code, int val) {
        try {
            Map<String,Integer> map = new HashMap<>(1);
            map.put(STATE,val);
            fastJsonTemp.opsForValue().set(concat(STATE_NAME_SPACE, code, STATE), map);
        } catch (Exception e) {
            log.error("setClientOnline Failed! [" + code + "]", e);
        }
    }


    public List getRealDatas(@NonNull String ptCode,@NonNull String code) {
        String pkey = concat(RDATA_NAME_SPACE, ptCode, code);
        Set<String> keys = fastJsonTemp.keys(pkey);
        System.out.println(keys);
        RedisSerializer<String> redisSerializer = (RedisSerializer<String>) fastJsonTemp.getKeySerializer();
        List result = fastJsonTemp.executePipelined((RedisCallback) redisConnection -> {
            redisConnection.openPipeline();
            Objects.requireNonNull(keys).stream().map(key -> Objects.requireNonNull(redisSerializer.serialize(key))).forEach(redisConnection::get);
            return null;
        });

        if(CollectionUtils.isNotEmpty(result))
        {
            return result;
        }
        else {
            return null;
        }
    }




    public List getClientStatus(@NonNull String code) {
        String pkey = concat(STATE_NAME_SPACE, code, "*");
        Set<String> keys = fastJsonTemp.keys(pkey);
        System.out.println(keys);
        Set<String> nKeys = new HashSet<>();
        if (keys.contains(concat(STATE_NAME_SPACE, code, ONLINE))) {
            nKeys.add(concat(STATE_NAME_SPACE, code, ONLINE));
        }
        if(keys.contains(concat(STATE_NAME_SPACE, code, STATE))) {
            nKeys.add(concat(STATE_NAME_SPACE, code, STATE));
        }
        if(keys.contains(concat(STATE_NAME_SPACE, code, ONLINE)))
        {
            nKeys.add(concat(STATE_NAME_SPACE, code, ONLINE,OFFLIMETIME));
            nKeys.add(concat(STATE_NAME_SPACE, code, ONLINE,ONLIMETIME));
        }

        RedisSerializer<String> redisSerializer = (RedisSerializer<String>) fastJsonTemp.getKeySerializer();
        List<Object> result = fastJsonTemp.executePipelined((RedisCallback) redisConnection -> {
            redisConnection.openPipeline();
            for(String key:nKeys)
            {
                redisConnection.get(redisSerializer.serialize(key));

            }
            return null;
        });

        if(CollectionUtils.isNotEmpty(result))
        {
            return result;
        }
        else {
            return null;
        }
    }

    public void insertRealData(@NonNull String code, @NonNull String ptCode, Map<String, PollutentParam> properties) {
        try {
            RedisRealData realData = RedisRealData.builder().mnCode(code).data(properties).build();
            fastJsonTemp.opsForValue().set(concat(RDATA_NAME_SPACE, ptCode, code), realData, 600, TimeUnit.SECONDS);
        } catch (Exception e) {
            log.error("insertRealData Failed! mn:[" + code + "]", e);
        }
    }

    public static void _insertRealData(@NonNull String code, @NonNull String ptCode, Map<String,PollutentParam> properties)
    {
        operator.insertRealData(code, ptCode, properties);
    }

    private String concat(Object... element) {
        if (isNull(element) || element.length == 0) {
            return null;
        }
        return Stream.of(element).filter(Objects::nonNull)
                .map(String::valueOf).filter(StringUtils::isNoneBlank).collect(joining(DELIMIT));
    }

}
